home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- These C++ classes are copyright 1990, by William Herrera.
- All those who put this code or its derivatives in a commercial product MUST
- mention this copyright in their documentation for users of the products in
- which this code or its derivative classes are used. Otherwise, this code
- may be freely distributed and freely used for any purpose.
-
- Enhancements: 1991 by David Orme
- * General cleanup.
- - I/O now takes advantage of C++ overloading.
- - Serial port I/O functionality now only in Serial class.
- - Modem functionality now only in Modem class.
- * Possible to easily implement file Xfr prots now.
- * CCITT CRC-16 class added -- 2-20-1991
- * BIOS Timer class added -- 2-22-1991
- * Optional timeout on all input routines added -- 2-25-1991
-
- ***************************************************************************/
-
- // File uart.cpp, class definitions for the uart class.
- // By William Herrera.
-
- // See your modem manual (I used MultiTech's) or the IBM Technical
- // reference manual for more information on the 8250 UART used in the PC.
-
- #include <stdio.h>
- #include <stdlib.h>
-
-
- #include "uart.hpp"
-
-
- // C++ 2.0 requires that static data members be declared globally
-
- char uart::old_intmask[NUM_PORTS];
- char uart::old_MCR[NUM_PORTS];
- char uart::old_IER[NUM_PORTS];
-
- const int uart::portvector_num[NUM_PORTS] = { 0xC, 0xB, 0xC, 0xB };
-
- const char uart::intmaskbit[NUM_PORTS] = { 0x10, 0x08, 0x10, 0x08 };
-
- #ifdef __TURBOC__
- DRIVER uart::old_driver[NUM_PORTS] = { NULL, NULL, NULL, NULL };
- #else ifdef __ZTC__
- void far * uart::old_driver[NUM_PORTS] = { NULL, NULL, NULL, NULL };
- #endif
-
- uart::uart() { ; }
-
- uart::~uart() { ; }
-
-
- // the following function sets up the PC for interrupt-driven serial
- // communications through the UART. Returns 0 for success, -1 for
- // port disallowed, -2 for uart interrupts not resettable.
- int uart::RegisterDriver(int portnum, DRIVER driv)
- {
- int retval;
- if(
- (portnum < 1) || (portnum > NUM_PORTS) ||
- (old_driver[portnum - 1] != NULL) )
- {
- fputs("uart::RegisterDriver() cannot set port requested.\n",
- stderr);
- retval = -1;
- }
- else
- {
- disable();
- // Hardware interrupts off til we change the settings.
- // Make sure DLAB of LSR is 0 to allow access to IER and MCR.
- SetLCR_DLAB(false);
- // Save old IER and MCR.
- old_IER[portnum -1] = GetIER();
- old_MCR[portnum- 1] = GetMCR();
- // Then check the UART for accessibility.
- SetIER(0);
- if(GetIER() != 0)
- {
- fputs("uart error: unable to reset IER\n", stderr);
- retval = -2;
- }
- else
- {
- // save the old interrupt mask.
- old_intmask[portnum - 1] = inportb(0x21);
-
- // reset vector to point to our handler.
- #ifdef __TURBOC__
- old_driver[portnum - 1] = getvect(portvector_num[portnum - 1]);
- setvect(portvector_num[portnum - 1], driv);
- #else ifdef __ZTC__
- unsigned int iseg, ioff;
- int_getvector(portvector_num[portnum - 1], &ioff, &iseg);
- old_driver[portnum - 1] = MK_FP(iseg, ioff);
- int_intercept(portvector_num[portnum - 1], driv, 0);
- #endif
- SetMCR(9); // turn on DTR and interrupts by modem (1|8).
- SetIER(13); // turn on data ready, line, modem ints (1|4|8).
-
- // Now enable controller for serial port interrupts.
- outportb( 0x21, (inportb(0x21) & ~(intmaskbit[portnum - 1])) );
-
- // set speed to a default baud rate of 19200.
- SetSpeed(19200);
- // Set port to default parameters of 8 data, 1 stop, no parity.
- SetParity(NOPAR);
- SetWordLength(8);
- SetStopBits(1);
-
- retval = 0;
- }
- enable();
- }
- return retval;
- }
-
- // This function resets the interrupt controller and UART and
- // generally cleans up after the RegisterDriver function.
- // Returns 0 on success, -1 on port not restorable.
- int uart::RestoreDriver(int portnum)
- {
- int retval;
- if( (portnum < 1) || (portnum > NUM_PORTS) ||
- (old_driver[portnum - 1] == NULL) )
- {
- fputs("UART Error: Cannot restore port.\n", stderr);
- retval = -1;
- }
- else
- {
- // reset the interrupt vector.
- disable();
- #ifdef __TURBOC__
- setvect(portvector_num[portnum - 1], old_driver[portnum - 1]);
- #else ifdef __ZTC__
- int_restore(portvector_num[portnum - 1]);
- #endif
- // reset the i8259 mask to its original state.
- outportb(0x21, old_intmask[portnum - 1]);
- // reset UART registers.
- SetIER(old_IER[portnum -1]);
- SetMCR(old_MCR[portnum - 1]);
- enable();
- old_driver[portnum - 1] = NULL;
- retval = 0;
- }
- return retval;
- }
-
- char uart::GetLCR()
- {
- return inportb(LCR());
- }
-
- char uart::GetDLL()
- {
- return inportb(DLL());
- }
-
- char uart::GetDLM()
- {
- return inportb(DLM());
- }
-
- char uart::GetLSR()
- {
- return inportb(LSR());
- }
-
- char uart::GetMCR()
- {
- return inportb(MCR());
- }
-
- char uart::GetMSR()
- {
- return inportb(MSR());
- }
-
- char uart::GetRBR()
- {
- return inportb(RBR());
- }
-
- char uart::GetIER()
- {
- return inportb(IER());
- }
-
- char uart::GetIIR()
- {
- return inportb(IIR());
- }
-
- boolean uart::GetLSR_THRE()
- {
- return (GetLSR() & 32) ? true : false;
- }
-
- void uart::SetLCR(char byte)
- {
- outportb(LCR(), byte);
- }
-
- void uart::SetDLL(char byte)
- {
- outportb(DLL(), byte);
- }
-
- void uart::SetDLM(char byte)
- {
- outportb(DLM(), byte);
- }
-
- void uart::SetLSR(char byte)
- {
- outportb(LSR(), byte);
- }
-
- void uart::SetMCR(char byte)
- {
- outportb(MCR(), byte);
- }
-
- void uart::SetMSR(char byte)
- {
- outportb(MSR(), byte);
- }
-
- void uart::SetTHR(char byte)
- {
- outportb(THR(), byte);
- }
-
- void uart::SetIER(char byte)
- {
- outportb(IER(), byte);
- }
-
- void uart::SetIER_Recieve(boolean bit)
- {
- SetIER( (bit) ? GetIER() | 1 : GetIER() & (~1) );
- }
-
- void uart::SetIER_Transmit(boolean bit)
- {
- SetIER( (bit) ? GetIER() | 2 : GetIER() & (~2) );
- }
-
- void uart::SetIER_Line(boolean bit)
- {
- SetIER( (bit) ? GetIER() | 4 : GetIER() & (~4) );
- }
-
- void uart::SetIER_Modem(boolean bit)
- {
- SetIER( (bit) ? GetIER() | 8 : GetIER() & (~8) );
- }
-
- void uart::SetLCR_DLAB(boolean bit)
- {
- SetLCR( (bit) ? GetLCR() | 128 : GetLCR() & (~128) );
- }
-
- void uart::SetLSR_DR(boolean bit)
- {
- SetLSR( (bit) ? GetLSR() | 1 : GetLSR() & (~1) );
- }
-
- void uart::SetBaudRate(int speed)
- {
- int divisor = 115200L / speed;
- char lsb = divisor & 0xFF;
- char msb = (divisor >> 8) & 0xFF;
- SetLCR_DLAB(true);
- SetDLL(lsb);
- SetDLM(msb);
- SetLCR_DLAB(false);
- }
-
- int uart::GetBaudRate()
- {
- SetLCR_DLAB(true);
- int lsb = GetDLL() & 0xFF;
- int msb = GetDLM() & 0xFF;
- SetLCR_DLAB(false);
- return ( 115200L / ((msb << 8) + lsb) );
- }
-
- void uart::SetParity(parity_t p)
- {
- SetLCR( (GetLCR() & 0xC7) | p);
- }
-
- parity_t uart::GetParity()
- {
- return (parity_t)(GetLCR() & 0x38);
- }
-
- void uart::SetWordLength(int len)
- {
- SetLCR( (GetLCR() & 0xFC) | ((len - 5) & 3) );
- }
-
- int uart::GetWordLength()
- {
- return (GetLCR() & 3) + 5;
- }
-
- void uart::SetStopBits(int num)
- {
- SetLCR( (GetLCR() & 0xFB) | ((num == 1) ? 0 : 4) );
- }
-
- int uart::GetStopBits()
- {
- return (GetLCR() & 4) ? 1 : 2;
- }
-
- void uart::SetBreak()
- {
- SetLCR(GetLCR() | 64);
- }
-
- void uart::StopBreak()
- {
- SetLCR(GetLCR() & (~64));
- }
-
- void uart::Pause(int msec)
- {
- // assumes the PC BIOS tick is 18.2 per second, or
- // 55 msec per tick.
- // DO NOT call this from an interrupt driver that uses the clock!
- union REGS regs;
- regs.x.ax = 0;
- int86(0x1A, ®s, ®s);
- int startcount = regs.x.dx;
- int endcount = startcount + (msec / 55);
- int i = startcount;
- while(i < endcount && i >= startcount)
- {
- regs.x.ax = 0;
- int86(0x1A, ®s, ®s);
- i = regs.x.dx;
- }
- }
-
- void uart::Break(int msec)
- {
- // assumes the PC BIOS tick is 18.2 per second, or
- // 55 msec per tick.
- // DO NOT call this from an interrupt driver that uses the clock!
- SetBreak();
- Pause(msec);
- StopBreak();
- }
-
- void uart::SetCTS(boolean bit)
- {
- SetMSR( (bit) ? (GetMSR() | 16) : (GetMSR() & (~16)) );
- }
-
- void uart::SetDSR(boolean bit)
- {
- SetMSR( (bit) ? (GetMSR() | 32) : (GetMSR() & (~32)) );
- }
-
- boolean uart::CarrierPresent()
- {
- // actually tests RLSD, bit 7 of MSR.
- return (GetMSR() & 128) ? true : false;
- }
-
- void uart::SetDTR(boolean bit)
- {
- SetMCR( (bit) ? (GetMCR() | 1) : (GetMCR() & (~1)) );
- }
-
- boolean uart::GetDTR()
- {
- return (GetMCR() & 1) ? true : false;
- }
-
- com_interrupt_t uart::GetIntrType()
- {
- int type = (int)GetIIR() & 0xFF;
- if(type & 1)
- return NONE_PENDING;
- int r;
- switch(type)
- {
- case 0:
- r = GetMSR();
- if(r & 4)
- return RING;
- else if (r & 128)
- return CARRIER;
- else
- return NO_CARRIER;
- case 2:
- r = GetLSR();
- if(r & 32) // THRE
- return TRANSMIT_READY;
- else
- return TRANSMIT_FALSE_ALARM;
- case 4:
- return RECEIVE_READY;
- case 6:
- r = GetLSR();
- if(r & 2) //
- return OVERRUN_ERROR;
- else if(r & 4)
- return PARITY_ERROR;
- else if(r & 8)
- return FRAMING_ERROR;
- else if(r & 16)
- return BREAK_RECEIVED;
- else
- return UNKNOWN_ERROR;
- default :
- return UNKNOWN_ERROR;
- }
- }
-
-
- int uart::GetChar()
- {
- // note: for this method to work, SetLCR_DLAB(false) must be called.
- return (GetLSR() & 1) ? ( (int)inportb(RBR()) & 0x00FF ) : -1;
- }
-
- void uart:: SendChar(char ch)
- {
- // note: for this method to work, SetLCR_DLAB(false) must be called.
- // this method works only if there is room in the transmit register.
- outportb(THR(), ch);
- }
-
- void uart::TransmitChar(char ch)
- {
- // similar to last one -- allows other to be overloaded separately
- outportb(THR(), ch);
- }
-
- int uart::ReceiveChar()
- {
- // similar to GetChar() -- allows other to be overloaded separately
- // note: for this method to work, SetLCR_DLAB(false) must be called.
- return (GetLSR() & 1) ? ( (int)inportb(RBR()) & 0x00FF ) : -1;
- }
-